﻿using DapperORM.Abstractions;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace DapperORM
{
    public static partial class SqlMapperEx
    {
        /// <summary>
        /// 默认IEntityTypeMapper
        /// </summary>
        public static Type DefaultEntityTypeMapper { get; set; } = typeof(DeaultEntityTypeMapper<>);

        /// <summary>
        /// 获取表名
        /// </summary>
        public static string GetTableName(Type type)
        {
            if (TypeTableName.TryGetValue(type.TypeHandle, out string name))
                return name;
            var entityMap = GetOrAddEntityTypeMapper(type);
            name = entityMap.MapTableName();
            TypeTableName[type.TypeHandle] = name;
            return name;
        }

        /// <summary>
        /// 获取或新增实体映射IEntityTypeMapper
        /// </summary>
        public static IEntityTypeMapper GetOrAddEntityTypeMapper(Type type)
        {
            return EntityTypeMapper.GetOrAdd(type.TypeHandle, rth =>
            {
                var entityMapType = type.Assembly.GetTypes().Where(m => m.IsGenericType && typeof(IEntityTypeMapper).IsAssignableFrom(m)
                && !m.IsGenericTypeDefinition && m.GetGenericArguments()[0] == type).FirstOrDefault() ?? DefaultEntityTypeMapper;
                if (entityMapType.IsGenericType)
                    entityMapType.MakeGenericType(type);
                return Activator.CreateInstance(entityMapType) as IEntityTypeMapper;
            });
        }

        /// <summary>
        /// 获取复合主键字段属性
        /// </summary>
        public static List<ColumnProperty> ComputedPropertiesCache(Type type)
        {
            //if (ComputedProperties.TryGetValue(type.TypeHandle, out IEnumerable<ColumnProperty> pi))
            //    return pi.ToList();

            //var computedProperties = TypePropertiesCache(type).Where(p => p.PropertyInfo.GetCustomAttributes(true).Any(a => a is ComputedAttribute)).ToList();
            //ComputedProperties[type.TypeHandle] = computedProperties;
            //return computedProperties;
            return new List<ColumnProperty>();
        }

        /// <summary>
        /// 获取非自增主键字段属性
        /// </summary>
        public static List<ColumnProperty> ExplicitKeyPropertiesCache(Type type)
        {
            if (ExplicitKeyProperties.TryGetValue(type.TypeHandle, out IEnumerable<ColumnProperty> pi))
                return pi.ToList();

            var explicitKeyProperties = TypePropertiesCache(type).Where(cp => cp.KeyType == KeyType.NotIdentity).ToList();
            ExplicitKeyProperties[type.TypeHandle] = explicitKeyProperties;
            return explicitKeyProperties;
        }

        /// <summary>
        /// 获取自增主键字段属性
        /// </summary>
        public static List<ColumnProperty> KeyPropertiesCache(Type type)
        {
            if (KeyProperties.TryGetValue(type.TypeHandle, out IEnumerable<ColumnProperty> pi))
                return pi.ToList();

            var keyProperties = TypePropertiesCache(type).Where(cp => cp.KeyType == KeyType.Identity).ToList();
            KeyProperties[type.TypeHandle] = keyProperties;
            return keyProperties;
        }

        /// <summary>
        /// 获取实体所有可写字段属性
        /// </summary>
        public static List<ColumnProperty> TypePropertiesCache(Type type)
        {
            if (TypeProperties.TryGetValue(type.TypeHandle, out IEnumerable<ColumnProperty> pis))
                return pis.ToList();

            var properties = type.GetProperties().Where(IsWriteable)
                .Select(m => new ColumnProperty { ColumnName = GetColumnName(m), PropertyInfo = m, KeyType = GetKeyType(m) }).ToArray();
            TypeProperties[type.TypeHandle] = properties;
            return properties.ToList();
        }

        /// <summary>
        /// add or update sqladapter
        /// </summary>
        /// <param name="name">sqladapter name, Internal processing to lowercase</param>
        /// <param name="adapter">ISqlAdapter</param>
        public static void AddOrUpdateSqlAdapter(string name, ISqlAdapter adapter)
        {
            if (!string.IsNullOrWhiteSpace(name) && adapter != null)
            {
                name = name.ToLower().Trim();
                AdapterDictionary[name] = adapter;
            }
        }

        /// <summary>
        /// ISqlAdapter
        /// </summary>
        /// <param name="connectionKey">具体DbConnection.GetType().Name</param>
        public static ISqlAdapter GetSqlAdapter(string? connectionKey)
        {
            if (string.IsNullOrWhiteSpace(connectionKey))
                return AdapterDictionary["default_"];
            connectionKey = connectionKey!.ToLower();
            if (AdapterDictionary.TryGetValue(connectionKey, out var adapter))
                return adapter;
            else
                return AdapterDictionary["default_"];
        }

        /// <summary>
        /// ISqlAdapter
        /// </summary>
        /// <param name="connection">IDbConnection</param>
        public static ISqlAdapter GetSqlAdapter(IDbConnection connection)
        {
            return GetSqlAdapter(connection?.GetType().Name);
        }

        /// <summary>
        /// 获取sql quote列名
        /// </summary>
        public static string GetQuoteColumnName(ISqlAdapter adapter, string columnName)
        {
            return $"{adapter.QuotePrefix}{columnName}{adapter.QuoteSuffix}";
        }

        /// <summary>
        /// 获取sql quote表名
        /// </summary>
        public static string GetQuoteTableName(ISqlAdapter adapter, string tableName)
        {
            return $"{adapter.QuotePrefix}{tableName}{adapter.QuoteSuffix}";
        }

        /// <summary>
        /// 获取sql参数名称
        /// </summary>
        public static string GetQuoteParamName(ISqlAdapter adapter, string paramName)
        {
            return $"{adapter.QuoteParamter}{paramName}";
        }
    }
}
